#ifndef __G_GAME_OBJECT_H__
#define __G_GAME_OBJECT_H__

#include <string>
#include <vector>

#include "GComponent.h"

#include "../../Foundation/GUtilities/GTypes.h"
#include "../../Foundation/GUtilities/GInstanceId.h"
#include "../../Foundation/GUtilities/GBitContainer.h"

namespace GEngine
{

	class GGameObject : public GUtil::GInstanceId<GGameObject>
	{
	friend class GVisitor;

	//! User hashmap for component container
	typedef std::vector<GGameObject*> ChildArray;
	typedef std::vector<GComponent*> ComponentArray;

	private:
		bool					Active;
		bool					Hidden;
		bool					Static;

		std::string				Name;

		ComponentArray			Components;

		GGameObject*			Parent;
		ChildArray				Children;

		GUtil::GMask			VisitorMask;

	protected:
								GGameObject();
		virtual					~GGameObject();

		virtual void			OnChildAppend(GGameObject* NewChild);
		virtual void			OnChildRemove(GGameObject* OldChild);
		virtual void			OnParentChange(GGameObject* NewParent);

	public:
		void					SetActive(bool Value);
		bool					GetActive() const;
		
		void					SetHidden(bool Value);
		bool					GetHidden() const;

		void					SetStatic(bool Value);
		bool					GetStatic() const;
		
		void					SetName(const char* String);
		const char*				GetName() const;

		// Component methods
		void					ClearComponents();
	
		void					AppendComponent(GComponent* Comp);

		void					RemoveComponent(const char* Name);
		void					RemoveComponent(GComponent* Comp);
	
		bool					ReplaceComponent(GComponent* NewComp, const char* OldComp);
		bool					ReplaceComponent(GComponent* NewComp, GComponent* OldComp);
	
		template<typename T>
		T*						FindComponent() const;
		GComponent*				FindComponent(const char* Name) const;

		// Graph methods
		void					SetVisitorMask(GUtil::GMask Mask);
		GUtil::GMask			GetVisitorMask() const;
		
		GGameObject*			GetParent() const;
		GUInt32					GetChildCount() const;

		GGameObject*			FindRoot() const;
		GGameObject*			FindChild(const char* Name) const;

		void					RemoveChild(GGameObject* Child);
		void					AppendChild(GGameObject* Child);
		bool					ReplaceChild(GGameObject* NewChild, GGameObject* OldChild);
	};

}; // namespace GGame

#endif